package com.snow.java.base.junit;

import com.snow.java.base.entity.Student;

import java.sql.SQLOutput;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @类名称：
 * @类描述：
 * @author: bingHeng
 * @Date 2019.04.06
 * @Version: 1.0
*/
public class MyStream3 {
    /**
     * Stream API的终止操作
     *
     * 查找与匹配
     *      allMatch:检查是否匹配所有元素
     *      anyMatch:检查是否至少匹配一个元素
     *      noneMatch:检查是否没有匹配所有元素
     *      findFirst:返回第一个元素
     *      findAny:返回当前流中的任意元素
     *      count:返回流中元素的总个数
     *      max:返回流中最大值
     *      min:返回流中最小值
     *
     * 归约
     *  reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的元素反复结合起来，得到一个值
     *
     * 收集
     *  collect:将流转寒为其他形式，接收一个Collector接口的实现，用于给Stream中的元做汇总的方法。
     *  Collector接口方法中的实现决定了如何对流执行收集操作（如List Map Set），但是Collectors实用类提供了很多方法，可以方便的创建常见的收集器实例
     */

    public static void main(String[] args) {
        List<Student> studentList = Arrays.asList(
                new Student(1, "张三", 2, 1, 85, Student.Status.BUSY),
                new Student(2, "李四", 2, 2, 60, Student.Status.BUSY),
                new Student(3, "王五", 2, 3, 100, Student.Status.FREE),
                new Student(4, "赵柳", 2, 4, 30, Student.Status.VOCATION),
                new Student(5, "大仙", 2, 5, 25, Student.Status.FREE),
                new Student(6, "小鬼", 2, 6, 74, Student.Status.VOCATION),
                new Student(1, "张三", 2, 1, 85, Student.Status.FREE),
                new Student(100, "张三", 2, 1, 85, Student.Status.BUSY)
        );

        // allMatch:检查是否匹配所有元素
        boolean b = studentList.stream().allMatch((e) -> e.getStatus().equals(Student.Status.BUSY));
        System.out.println(b);

        // anyMatch:检查是否至少匹配一个元素
        boolean b1 = studentList.stream().anyMatch((e) -> e.getStatus().equals(Student.Status.BUSY));
        System.out.println(b1);

        // noneMatch:检查是否没有匹配所有元素 == 检查是否有匹配的元素
        boolean b2 = studentList.stream().noneMatch((e) -> e.getStatus().equals(Student.Status.FREE));
        System.out.println(b2);

        // findFirst:返回第一个元素
        Optional<Student> first = studentList.stream().findFirst();
        // 判断返回的元素是否为null, 如果为null则可以自己定义一个对象，避免空指针异常
        Student student = first.orElse(new Student());
        System.out.println(student);

        // findAny:返回当前流中的任意元素
        Optional<Student> first1 = studentList.stream().filter((e) -> e.getStatus().equals(Student.Status.FREE)).findFirst();
        Student student1 = first1.orElse(new Student());
        System.out.println(student1);

        // count:返回流中元素的总个数
        long count = studentList.stream().filter((e) -> e.getStatus().equals(Student.Status.VOCATION)).count();
        System.out.println(count);

        // max:返回流中最大值  根据分数
        Optional<Student> max = studentList.stream().max(Comparator.comparingInt(Student::getScore));
        Student student2 = max.orElse(new Student());
        System.out.println(student2);

        // min:返回流中最小值
        Optional<Student> min = studentList.stream().min(Comparator.comparingInt(Student::getScore));
        Student student3 = min.orElse(new Student());
        System.out.println(student3);

        // 归约

        // 求和
        /**
         * reduce(T identity, BinaryOperator)  第一个参数为初始值
         * 归约的做法：
         *      首先将初始值作为x，从流中取出元素作为y，然后x+y，将x+y的计算结果给x重新赋值，依次计算
         */

        System.out.println("===========================我是黄金分割线1==============================");
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Integer reduce = integerList.stream().reduce(1, (x, y) -> x + y);
        System.out.println(reduce);

        // 计算所有学生分数的总和: map-reduce模式：非常出名，因为Goole用它来做网络搜索排名而出名
        Integer integer = studentList.stream().map(Student::getScore).reduce(Integer::sum).orElse(0);
        System.out.println(integer);



        // 收集
        System.out.println("===========================我是黄金分割线2==============================");

        // 将学生集合中所有的名字收集到一个新的集合中，并打印输出
        studentList.stream().map(Student::getName).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println("----------");
        studentList.stream().map(Student::getName).collect(Collectors.toSet()).forEach(System.out::println);
        System.out.println("----------");

        // 放入HashSet、LinkList等自己指定的集合中去
        studentList.stream().map(Student::getName).collect(Collectors.toCollection(HashSet::new)).forEach(System.out::println);
        System.out.println("----------");

        // 总和
        Long collect = (long) studentList.size();
        System.out.println(collect);

        // 平均值
        Double collect1 = studentList.stream().collect(Collectors.averagingInt(Student::getScore));
        System.out.println(collect1);

        // 总和
        IntSummaryStatistics collect2 = studentList.stream().collect(Collectors.summarizingInt(Student::getScore));
        System.out.println(collect2);

        // 最大值
        Optional<Student> collect3 = studentList.stream().max(Comparator.comparingInt(Student::getScore));
        System.out.println(collect3.get());

        // 分组  按照学生的状态进行分组
        Map<Student.Status, List<Student>> collect4 = studentList.stream().collect(Collectors.groupingBy(Student::getStatus));
        System.out.println(collect4);

        // 多级分组  先按照状态分组，状态相同按照分数分组
        Map<Student.Status, Map<String, List<Student>>> collect5 = studentList.stream().collect(Collectors.groupingBy(Student::getStatus, Collectors.groupingBy(Student::getName)));
        System.out.println(collect5);

        // 分片 按照分数进行分片，及格的一个片，不及格的一个片
        Map<Boolean, List<Student>> collect6 = studentList.stream().collect(Collectors.partitioningBy((e) -> e.getScore() >= 60));
        System.out.println(collect6);

        // 另一种方式获取组函数：求和、平均值、最大最小等
        IntSummaryStatistics collect7 = studentList.stream().collect(Collectors.summarizingInt(Student::getScore));
        System.out.println(collect7.getMax());
        System.out.println(collect7.getMin());
        System.out.println(collect7.getAverage());
        System.out.println(collect7.getCount());
        System.out.println(collect7.getSum());

        // 字符串连接
        String collect8 = studentList.stream().map(Student::getName).collect(Collectors.joining());
        String collect9 = studentList.stream().map(Student::getName).collect(Collectors.joining("-"));
        System.out.println(collect8);
        System.out.println(collect9);
    }
}
